'use strict'

###*
 # @ngdoc directive
 # @name xoceanApp.directive:pagination
 # @description
 # # pagination
 # Angular-ui pagination
###
angular.module('xoceanApp')
  .controller('PaginationCtrl', ($scope, $attrs, $parse)->
    self = this
    ngModelCtrl = { $setViewValue: angular.noop() }
    setNumPages = if $attrs.numPages then $parse($attrs.numPages).assign else angular.noop()
    this.init = (_ngModelCtrl, config)->
      ngModelCtrl = _ngModelCtrl
      this.config = config

      ngModelCtrl.$render = ->
        self.render()

      if $attrs.itemsPerPage
        $scope.$parent.$watch $parse($attrs.itemsPerPage), (value)->
          self.itemsPerPage = parseInt(value, 10)
          $scope.totalPages = self.calculateTotalPages()
          return
      else
        this.itemsPerPage = config.itemsPerPage
      return

    this.calculateTotalPages = ->
      totalPages = if this.itemsPerPage < 1 then 1 else Math.ceil($scope.totalItems / this.itemsPerPage)
      return Math.max(totalPages || 0, 1)

    this.render = ->
      $scope.page = parseInt(ngModelCtrl.$viewValue, 10) or 1
      return

    $scope.selectPage = (page)->
      if $scope.page isnt page and page > 0 and page <= $scope.totalPages
        ngModelCtrl.$setViewValue(page)
        ngModelCtrl.$render()
      return

    $scope.getText = (key)->
      return $scope[key + 'Text'] || self.config[key + 'Text']
    
    $scope.noPrevious = ->
      return $scope.page is 1

    $scope.noNext = ->
      return $scope.page is $scope.totalPages

    $scope.$watch 'totalItems', ->
      $scope.totalPages = self.calculateTotalPages()
      return

    $scope.$watch 'totalPages', (value)->
      setNumPages($scope.$parent, value)
      if $scope.page > value
        $scope.selectPage value
      else
        ngModelCtrl.$render()

    return

  ).constant('paginationConfig', {
    itemsPerPage: 10
    boundaryLinks: false
    directionLinks: true
    firstText: 'First'
    previousText: 'Previous'
    nextText: 'Next'
    lastText: 'Last'
    rotate: true
  }).directive('pagination', ($parse, paginationConfig)->
    restrict: 'EA'
    scope:
      totalItems: '='
      firstText: '@'
      previousText: '@'
      nextText: '@'
      lastText: '@'

    require: ['pagination', '?ngModel']
    controller: 'PaginationCtrl'
    replace: true
    template: """
      <ul class="pagination">
        <li ng-if="boundaryLinks" ng-class="{disabled: noPrevious()}"><a href ng-click="selectPage(1)">{{getText('first')}}</a></li>
        <li ng-if="directionLinks" ng-class="{disabled: noPrevious()}"><a href ng-click="selectPage(page - 1)">{{getText('previous')}}</a></li>
        <li ng-repeat="page in pages track by $index" ng-class="{active: page.active}"><a href ng-click="selectPage(page.number)">{{page.text}}</a></li>
        <li ng-if="directionLinks" ng-class="{disabled: noNext()}"><a href ng-click="selectPage(page + 1)">{{getText('next')}}</a></li>
        <li ng-if="boundaryLinks" ng-class="{disabled: noNext()}"><a href ng-click="selectPage(totalPages)">{{getText('last')}}</a></li>
      </ul>
    """
    link: (scope, element, attrs, ctrls) ->
      paginationCtrl = ctrls[0]
      ngModelCtrl = ctrls[1]
      return if not ngModelCtrl

      # Setup configuration parameters
      maxSize = if angular.isDefined(attrs.maxSize) then scope.$parent.$eval(attrs.maxSize) else paginationConfig.maxSize
      rotate = if angular.isDefined(attrs.rotate) then scope.$parent.$eval(attrs.rotate) else paginationConfig.rotate
      scope.boundaryLinks = if angular.isDefined(attrs.boundaryLinks) then scope.$parent.$eval(attrs.boundaryLinks) else paginationConfig.boundaryLinks
      scope.directionLinks = if angular.isDefined(attrs.directionLinks) then scope.$parent.$eval(attrs.directionLinks) else paginationConfig.directionLinks
  
      paginationCtrl.init ngModelCtrl, paginationConfig
      if attrs.maxSize
        scope.$parent.$watch $parse(attrs.maxSize), (value)->
          maxSize = parseInt value, 10
          paginationCtrl.render()

      makePage = (number, text, isActive)->
        return {
          number: number
          text: text
          active: isActive
        }

      getPages = (currentPage, totalPages)->
        pages = []
        startPage = 1
        endPage = totalPages
        isMaxSized = angular.isDefined(maxSize) and maxSize < totalPages

        if isMaxSized
          if rotate
            startPage = Math.max(currentPage - Math.floor(maxSize/2), 1)
            endPage = startPage + maxSize - 1

            if endPage > totalPages
              endPage = totalPages
              startPage = endPage - maxSize + 1
          else
            startPage = ((Math.ceil(currentPage / maxSize) - 1) * maxSize) + 1
            endPage = Math.min(startPage + maxSize - 1, totalPages)

        number = startPage
        while number <= endPage
          page = makePage(number, number, number is currentPage)
          pages.push page
          number++

        if isMaxSized and not rotate
          if startPage > 1
            previousPageSet = makePage(startPage - 1, '...', false)
            pages.unshift previousPageSet

          if endPage < totalPages
            nextPageSet =  makePage(endPage + 1, '...', false)
            pages.push nextPageSet

        return pages

      originalRender = paginationCtrl.render
      paginationCtrl.render = ->
        originalRender()
        if scope.page > 0 and scope.page <= scope.totalPages
          scope.pages = getPages(scope.page, scope.totalPages)

        return
  )
